package org.example.protocol;

import cn.hutool.core.util.IdUtil;
import lombok.Data;
import org.artifact.core.context.packet.NetworkPacket;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Supplier;

public class ClientNetworkProtocolForJava
{
    interface AbstractDTO {
        Map<Object,Object> toMap(Map<Object,Object> map);
        Object forMap(Map<Object,Object> map);
    }


    @Data
    /** 玩家简单信息 */
    static class PlayerInfoDTO implements AbstractDTO{
        /** 用户ID */
        public long Uid;
        /** 玩家ID */
        public long Pid;
        /** 昵称 */
        public java.lang.String Name;
        /** 等级 */
        public int Lvl;
        /** 经验 */
        public int Exp;
        /** 头像 */
        public int Icon;
        /** 类型 */
        public int Type;

        public Map<Object,Object> toMap(Map<Object,Object> map){
            map.put(115792, DtoSerializationProvider.tryEncoder(this.Uid));
            map.put(110987, DtoSerializationProvider.tryEncoder(this.Pid));
            map.put(3373707, DtoSerializationProvider.tryEncoder(this.Name));
            map.put(107554, DtoSerializationProvider.tryEncoder(this.Lvl));
            map.put(100893, DtoSerializationProvider.tryEncoder(this.Exp));
            map.put(3226745, DtoSerializationProvider.tryEncoder(this.Icon));
            map.put(3575610, DtoSerializationProvider.tryEncoder(this.Type));
            return map;
        }
        public Object forMap(Map<Object,Object> map){
            this.Uid = (long)DtoSerializationProvider.tryDecoder(map.get(115792));
            this.Pid = (long)DtoSerializationProvider.tryDecoder(map.get(110987));
            this.Name = (java.lang.String)DtoSerializationProvider.tryDecoder(map.get(3373707));
            this.Lvl = (int)DtoSerializationProvider.tryDecoder(map.get(107554));
            this.Exp = (int)DtoSerializationProvider.tryDecoder(map.get(100893));
            this.Icon = (int)DtoSerializationProvider.tryDecoder(map.get(3226745));
            this.Type = (int)DtoSerializationProvider.tryDecoder(map.get(3575610));
            return this;
        }
    }



    @Data
    /** 玩家信息 */
    static class PlayerDTO implements AbstractDTO{
        /** 基本信息 */
        public PlayerInfoDTO PlayerInfo;

        public Map<Object,Object> toMap(Map<Object,Object> map){
            map.put(2095520559, DtoSerializationProvider.tryEncoder(this.PlayerInfo));
            return map;
        }
        public Object forMap(Map<Object,Object> map){
            this.PlayerInfo = (PlayerInfoDTO)DtoSerializationProvider.tryDecoder(map.get(2095520559));
            return this;
        }
    }









    static class PlayerModule{
        public static final int ENTER_GAME = 450960106;
        public static final int NOTIFY_PLAYER = 450970506;

        public static void disp(NetworkPacket packet) {
            int command = packet.getHeader(NetworkHeader.COMMAND);
            int module = command >> 16;
            int method = module << 16 ^ command;
            switch (method) {
                case 6890:
                    _enterGame(packet);
                    break;
                case 17290:
                    _notifyPlayer(packet);
                    break;
            }
        }


        /// <summary>
        /// 进入游戏
        /// </summary>
        public static void enterGame(NetClient client, java.lang.String loginServerId, java.lang.String token,EnterGameListener listener) {
            NetworkPacket packet = new NetworkPacket();
            String messageId = IdUtil.simpleUUID();
            packet.setHeader(NetworkHeader.ID, messageId);
            packet.setHeader(NetworkHeader.COMMAND, 450960106);
            packet.setHeader(NetworkHeader.MODULE, 6881);
            packet.setHeader(NetworkHeader.METHOD, 6890);
            packet.setHeader(NetworkHeader.TYPE, NetworkHeader.TYPE_DEFAULT);

            packet.getBody().put(451300935, DtoSerializationProvider.tryEncoder(loginServerId));

            packet.getBody().put(110541305, DtoSerializationProvider.tryEncoder(token));

            client.AsyncSend(packet);

            // 注册监听
            if(listener!=null){
                ProtocolLListener.registerRequestListener(messageId,listener);
            }
        }

        /// <summary>
        /// 进入游戏-解码
        /// </summary>
        private static void _enterGame(NetworkPacket packet) {
            String messageId = (String)packet.getHeader(NetworkHeader.ID);
            MessageListener listener = ProtocolLListener.getRequestListener(messageId);
            if(listener!=null){
                int _code = (int)packet.getHeader(NetworkHeader.STATUS);
                PlayerDTO player = null;
                int index = 0;
                if(_code == 0)
                {
                    player = (PlayerDTO)DtoSerializationProvider.tryDecoder(packet.getBody().get(-985752863));
                    index = (int)DtoSerializationProvider.tryDecoder(packet.getBody().get(100346066));
                }
                else
                {
                    ProtocolLListener.execErrorListener(_code, packet);
                }
                // 执行监听
                ((EnterGameListener)listener).exec(_code, player, index);
                // 移除监听
                ProtocolLListener.removeRequestListener(messageId);
            }
        }

        /// <summary>
        /// 进入游戏-监听
        /// </summary>
        //public delegate void EnterGameListener(int _code, PlayerDTO player, int index);
        @FunctionalInterface
        interface EnterGameListener  extends MessageListener {void exec(int _code, PlayerDTO player, int index);}

        /// <summary>
        /// 推送-解码
        /// </summary>
        private static void _notifyPlayer(NetworkPacket packet) {
            int command = (int)packet.getHeader(NetworkHeader.COMMAND);
            MessageListener listener = ProtocolLListener.getNotifyListener(command);
            if(listener!=null){
                java.lang.String loginServerId = null;
                java.lang.String token = null;

                loginServerId = (java.lang.String)DtoSerializationProvider.tryDecoder(packet.getBody().get(451300935));
                token = (java.lang.String)DtoSerializationProvider.tryDecoder(packet.getBody().get(110541305));
                // 执行监听
                ((NotifyPlayerListener)listener).exec(loginServerId ,token);
            }

        }


        /// <summary>
        /// 推送-监听
        /// </summary>
        //public delegate void NotifyPlayerListener(java.lang.String loginServerId ,java.lang.String token);
        @FunctionalInterface
        interface NotifyPlayerListener  extends MessageListener {void exec(java.lang.String loginServerId ,java.lang.String token);}
    }

    // 消息路由
    static class _Dispatcher {
        public static void disp(NetworkPacket packet) {
            // 取得模块ID
            int command = (int)packet.getHeader(NetworkHeader.COMMAND);
            int module = command >> 16;
            switch (module)
            {
                case 6881:
                    PlayerModule.disp(packet);
                    break;
                default:
                    break;
            }
        }
    }


    static class DtoSerializationProvider{
        static Map<Integer, Supplier<? extends AbstractDTO>> cache = new HashMap<>();
        static Map<String, Integer> codes = new HashMap<String, Integer>();
        static
        {
            // 玩家简单信息
            cache.put(1102355472,() -> new PlayerInfoDTO());
            // 玩家信息
            cache.put(131897118,() -> new PlayerDTO());

            // 玩家简单信息
            codes.put("PlayerInfoDTO",1102355472);
            // 玩家信息
            codes.put("PlayerDTO",131897118);
        }

        // 尝试编码
        public static Object tryEncoder(Object obj)
        {
            if (obj instanceof AbstractDTO)
            {
                String typeName = obj.getClass().getSimpleName();
                if(codes.containsKey(typeName)){
                    int structCode = codes.get(typeName);
                    Map<Object, Object> dict = new HashMap<>();
                    dict.put(NetworkHeader.STRUCT_CODE,structCode);
                    return ((AbstractDTO)obj).toMap(dict);
                }
            }
            return obj;
        }

        // 尝试解码
        public static Object tryDecoder(Object obj)
        {
            if (obj instanceof Map)
            {
                Map<Object, Object> dict = (Map<Object, Object>)obj;
                if (dict.containsKey(NetworkHeader.STRUCT_CODE))
                {
                    int structCode = (int)dict.get(NetworkHeader.STRUCT_CODE);
                    if (DtoSerializationProvider.cache.containsKey(structCode))
                    {
                        AbstractDTO dto = cache.get(structCode).get();
                        return dto.forMap(dict);
                    }
                }
            }
            return obj;
        }
    }

    /**
    class ArtifactProtocolStreamBuffer : ArtifactStreamBuffer
    {
        public static final int STRUCT_CODE = 183928832;

        public ArtifactProtocolStreamBuffer(byte[] bytes = null) : base(bytes)
        {

        }

        public void WriteObject(object value)
        {
            if (value is AbstractDTO)
            {
                Map<Object,Object> table = new HashMap<Object,Object>();
                ((AbstractDTO)value).toMap(table);
                table.Add(STRUCT_CODE, DtoSerializationProvider.structCode(value.GetType().Name));
                WriteDict(table);
            }
            else
            {
                base.WriteObject(value);
            }
        }

        public object ReadObject()
        {
            MarkReaderIndex();
            byte tag = Read();
            ResetReaderIndex();
            if (tag == ArtifactBufferCoder.DICT || ArtifactBufferCoder.DICT_SUB_TYPE.ContainsVal(tag))
            {
                Map<Object,Object> map = ReadDict();
                if (map.ContainsKey(STRUCT_CODE))
                {
                    int structCode = (int)map[STRUCT_CODE];
                    AbstractDTO dto = DtoSerializationProvider.create(structCode);
                    return dto.forMap(map);
                }
                else
                {
                    return map;
                }

            }
            else {
                return base.ReadObject();
            }
        }
    }

    class SimpleDecoder : Decoder
    {
        public NetworkPacket Handler(NetClient client, byte[] data)
        {
            using (ByteBuffer byteBuffer = new ArtifactProtocolStreamBuffer(data))
            {
                NetworkPacket packet = new NetworkPacket();
                packet.ForByteBuff(byteBuffer);
                return packet;
            }
        }
    }

    class SimpleEncoder : Encoder
    {
        public byte[] Handler(NetClient client, NetworkPacket packet)
        {
            using (ByteBuffer byteBuffer = new ArtifactProtocolStreamBuffer())
            {
                byteBuffer.MarkWriterIndex();
                byteBuffer.Write(new byte[4]);
                packet.ToByteBuff(byteBuffer);
                int length = (int)byteBuffer.GetLength();
                byteBuffer.ResetWriterIndex();
                byteBuffer.Write(BufferUtil.GetByte(length - 4));
                return byteBuffer.ToArray();
            }
        }
    }
    */
    class NetworkHeader
    {
        public static final int STRUCT_CODE = 183928832;


        /** 唯一表示 */
        public static final int ID = 0;
        /** 命令 */
        public static final int COMMAND = 1;
        /** 状态 */
        public static final int STATUS = 2;
        /** 模块 */
        public static final int MODULE = 3;
        /** 方法 */
        public static final int METHOD = 4;
        /** 类型 */
        public static final int TYPE = 5;
        /** 标签 */
        public static final int TAG = 6;

        /** 后续可扩展加密方式，验证方式、校验和等等 */












        /** 类型-默认包 */
        public static final int TYPE_DEFAULT = 1;
        /** 类型-心跳包 */
        public static final int TYPE_HEARTBEAT = 2;
        /** 类型-确认包 */
        public static final int TYPE_ACK = 3;
    }

    interface MessageListener{}

    interface NetClient{
        void AsyncSend(NetworkPacket packet);
    }

    static class ProtocolLListener
    {

        private static Map request = new HashMap();

        private static Map notify = new HashMap();

        private static BiConsumer<Integer,NetworkPacket> errorListener = null;

        public static void registerErrorListener(BiConsumer<Integer,NetworkPacket> errorListener)
        {
            ProtocolLListener.errorListener = errorListener;
        }

        public static void removeErrorListener()
        {
            ProtocolLListener.errorListener = null;
        }

        public static void execErrorListener(int _code, NetworkPacket packet) {
            if (errorListener != null) {
                errorListener.accept(_code, packet);
            }
        }

        public static void registerNotifyListener(int command, MessageListener listener)
        {
            notify.put(command, listener);
        }

        public static void registerRequestListener(String messageId, MessageListener listener)
        {
            request.put(messageId, listener);
        }

        public static void removeNotifyListener(int command)
        {
            notify.remove(command);
        }

        public static void removeRequestListener(String messageId)
        {
            request.remove(messageId);
        }

        public static MessageListener getNotifyListener(int command)
        {
            return (MessageListener)notify.get(command);
        }

        public static MessageListener getRequestListener(String messageId)
        {
            return (MessageListener)request.get(messageId);
        }

        public static void clearNotifyListener()
        {
            notify.clear();
        }

        public static void clearRequestListener()
        {
            request.clear();
        }
    }
}